// src/main/java/com/yin/waimai/service/impl/AmapWebServiceImpl.java
package com.yin.waimai.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yin.waimai.config.AmapConfig;
import com.yin.waimai.model.Address;
import com.yin.waimai.service.AmapWebService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Service
public class AmapWebServiceImpl implements AmapWebService {

    private static final Logger log = LoggerFactory.getLogger(AmapWebServiceImpl.class);

    private final AmapConfig amapConfig;
    private final ObjectMapper objectMapper;
    private final HttpClient httpClient;

    private static final String GEOCODE_URL_BASE = "https://restapi.amap.com/v3/geocode/geo";
    private static final String DRIVING_ROUTE_URL_BASE = "https://restapi.amap.com/v3/direction/driving";

    // --- RouteInfo 静态内部类定义 ---
    public static class RouteInfo {
        private List<List<Double>> pathCoordinates;
        private Integer distanceMeters;

        public RouteInfo(List<List<Double>> pathCoordinates, Integer distanceMeters) {
            this.pathCoordinates = pathCoordinates;
            this.distanceMeters = distanceMeters;
        }

        public List<List<Double>> getPathCoordinates() { return pathCoordinates; }
        public Integer getDistanceMeters() { return distanceMeters; }
        public boolean isValid() { return distanceMeters != null && distanceMeters >= 0; } // Distance is primary for fee
        public boolean hasValidPath() { return pathCoordinates != null && !pathCoordinates.isEmpty(); }
    }
    // --- RouteInfo 定义结束 ---

    @Autowired
    public AmapWebServiceImpl(AmapConfig amapConfig, ObjectMapper objectMapper) {
        this.amapConfig = amapConfig;
        this.objectMapper = objectMapper;
        this.httpClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_1_1)
                .connectTimeout(Duration.ofSeconds(10))
                .build();
    }

    @Override
    public Optional<String> geocodeAddress(String address, String city) {
        URI uri = null;
        try {
            uri = UriComponentsBuilder
                    .fromHttpUrl(GEOCODE_URL_BASE)
                    .queryParam("key", amapConfig.getWebServiceKey())
                    .queryParam("address", address)
                    .queryParam("city", city)
                    .queryParam("output", "json")
                    .encode(StandardCharsets.UTF_8)
                    .build(false)
                    .toUri();

            log.debug("Geocode URI (java.net.http.HttpClient): {}", uri.toString());
            HttpRequest httpRequest = HttpRequest.newBuilder().uri(uri)
                    .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
                    .GET().timeout(Duration.ofSeconds(15)).build();
            HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
            String responseBody = httpResponse.body();
            log.debug("Geocode response (from java.net.http.HttpClient): {}", responseBody);

            if (httpResponse.statusCode() == 200 && responseBody != null) {
                JsonNode root = objectMapper.readTree(responseBody);
                if ("1".equals(root.path("status").asText())) {
                    JsonNode geocodes = root.path("geocodes");
                    if (geocodes.isArray() && geocodes.size() > 0) {
                        String location = geocodes.get(0).path("location").asText();
                        if (!location.isEmpty()) {
                            log.info("Successfully geocoded (from java.net.http.HttpClient) '{}' to {}", address, location);
                            return Optional.of(location);
                        } else { log.warn("Geocode successful (status 1 from java.net.http.HttpClient), but location string is empty. Full response: {}", responseBody); }
                    } else { log.warn("Geocode successful (status 1 from java.net.http.HttpClient), but geocodes array is empty or not found. Full response: {}", responseBody); }
                } else { log.warn("Geocode failed (from java.net.http.HttpClient) for '{}', Amap status: {}, info: {}, Full response: {}", address, root.path("status").asText(), root.path("info").asText(), responseBody); }
            } else { log.warn("Amap Geocoding HTTP request itself failed (from java.net.http.HttpClient) for address '{}'. Status code: {}, Body: {}", address, httpResponse.statusCode(), httpResponse.body()); }
        } catch (java.io.IOException | InterruptedException e) { log.error("IOException or InterruptedException during geocoding (from java.net.http.HttpClient) for URI '{}': {}", (uri != null ? uri.toString() : "URI_NOT_BUILT_OR_ERROR_EARLY"), e.getMessage(), e);
        } catch (Exception e) { log.error("General error during geocoding (from java.net.http.HttpClient) for URI '{}'", (uri != null ? uri.toString() : "URI_NOT_BUILT_OR_ERROR_EARLY"), e); }
        return Optional.empty();
    }

    @Override
    public Optional<RouteInfo> getDrivingRoute(String originLngLat, String destinationLngLat) { // 返回类型修改
        List<List<Double>> coords = new ArrayList<>();
        Integer distance = null;
        URI uri = null;
        try {
            uri = UriComponentsBuilder
                    .fromHttpUrl(DRIVING_ROUTE_URL_BASE)
                    .queryParam("key", amapConfig.getWebServiceKey())
                    .queryParam("origin", originLngLat)
                    .queryParam("destination", destinationLngLat)
                    .queryParam("extensions", "all") // extensions=all to get distance and steps
                    .queryParam("output", "json")
                    .encode(StandardCharsets.UTF_8)
                    .build(false)
                    .toUri();

            log.debug("Driving route URI (java.net.http.HttpClient): {}", uri.toString());
            HttpRequest httpRequest = HttpRequest.newBuilder().uri(uri)
                    .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
                    .GET().timeout(Duration.ofSeconds(20)).build();
            HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
            String responseBody = httpResponse.body();
            log.debug("Driving route response (from java.net.http.HttpClient): {}", responseBody);

            if (httpResponse.statusCode() == 200 && responseBody != null) {
                JsonNode root = objectMapper.readTree(responseBody);
                if ("1".equals(root.path("status").asText()) && root.hasNonNull("route")) {
                    JsonNode pathsNode = root.path("route").path("paths");
                    if (pathsNode.isArray() && pathsNode.size() > 0) {
                        JsonNode firstPath = pathsNode.get(0);
                        if (firstPath.hasNonNull("distance")) {
                            distance = firstPath.path("distance").asInt(); // 距离是整数，单位米
                            log.info("Route distance: {} meters", distance);
                        }

                        JsonNode steps = firstPath.path("steps");
                        if (steps.isArray()) {
                            for (JsonNode step : steps) {
                                String polyline = step.path("polyline").asText();
                                if (!polyline.isEmpty()) {
                                    String[] points = polyline.split(";");
                                    for (String point : points) {
                                        String[] parts = point.split(",");
                                        if (parts.length == 2) {
                                            try {
                                                coords.add(Arrays.asList(
                                                        Double.parseDouble(parts[0]),
                                                        Double.parseDouble(parts[1])
                                                ));
                                            } catch (NumberFormatException ex) {
                                                log.warn("Invalid coordinate format in polyline step: {}", point, ex);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        // 即使路径点为空，但如果距离有效，也认为RouteInfo部分有效
                        if (distance != null) {
                            log.info("Successfully planned driving route (from java.net.http.HttpClient) from {} to {}. Points count: {}, Distance: {}m", originLngLat, destinationLngLat, coords.size(), distance);
                            return Optional.of(new RouteInfo(coords, distance));
                        } else {
                            log.warn("Driving route planning successful (status 1), but distance is null. Full response: {}", responseBody);
                        }
                    } else {
                        log.warn("Driving route planning successful (status 1 from java.net.http.HttpClient), but no paths found. Full response: {}", responseBody);
                    }
                } else {
                    log.warn("Driving route planning failed (from java.net.http.HttpClient). Amap status: {}, Info: {}. Full response: {}",
                            root.path("status").asText(),
                            root.path("info").asText(),
                            responseBody);
                }
            } else {
                log.warn("Amap Driving Route HTTP request itself failed (from java.net.http.HttpClient). Status code: {}, Body: {}",
                        httpResponse.statusCode(), httpResponse.body());
            }
        } catch (java.io.IOException | InterruptedException e) {
            log.error("IOException or InterruptedException during route planning (from java.net.http.HttpClient) for URI '{}': {}", (uri != null ? uri.toString() : "URI_NOT_BUILT_OR_ERROR_EARLY"), e.getMessage(), e);
        } catch (Exception e) {
            log.error("General error during route planning (from java.net.http.HttpClient) for URI '{}'", (uri != null ? uri.toString() : "URI_NOT_BUILT_OR_ERROR_EARLY"), e);
        }
        return Optional.empty(); // 如果任何步骤失败，返回 empty
    }

    @Override
    public Optional<RouteInfo> getOrderRoutePath(Address shipperAddress, Address recipientAddress) { // 返回类型修改
        if (shipperAddress == null || recipientAddress == null) {
            log.warn("Shipper or Recipient address is null, cannot plan route.");
            return Optional.empty();
        }
        String shipperFull = shipperAddress.getFullAddress();
        String recipientFull = recipientAddress.getFullAddress();

        Optional<String> originOpt = geocodeAddress(shipperFull, shipperAddress.getCity());
        Optional<String> destOpt = geocodeAddress(recipientFull, recipientAddress.getCity());

        if (originOpt.isPresent() && destOpt.isPresent()) {
            return getDrivingRoute(originOpt.get(), destOpt.get());
        } else {
            log.warn("无法获取有效的起点或终点坐标进行路径规划。Shipper geocode success: {}, Recipient geocode success: {}", originOpt.isPresent(), destOpt.isPresent());
            return Optional.empty();
        }
    }
}